<template>
  <div class="box">
    <div id="cesiumContainer" />
    <div class="div">
      <button @click="drawExtent">绘制范围</button>
      <button @click="induationAnalysis">淹没分析</button>
      <button @click="clearAllEntities">清除</button>
      <div>最大高度：<input type="text" v-model="maxWaterHeight" />米</div>
      <div>最小高度：<input type="text" v-model="minWaterHeight" />米</div>
      <div>预警高度：<input type="text" v-model="warningWaterHeight" />米</div>
      <div>淹没速度：<input type="text" v-model="speed" />m/s</div>
      <div>实时高度: <span></span> m</div>
    </div>
  </div>
</template>
 
<script>
import * as turf from "@turf/turf";

let activeShapePoints = [];
let floatingPoint = undefined;
let activeShape = undefined;
let handler = undefined;
export default {
  data() {
    return {
      isDraw: false,
      maxWaterHeight: 2000,
      minWaterHeight: 0,
      warningWaterHeight: 0, // 预警高度
      waterHeight: 0,
      waterHeightShow: false,
      speed: "1",
      waterHeightTimeer: 0,
      waterPrimitive: undefined,
      tempEntities: [],
      viewModel: {
        emissionRate: 5,
        gravity: 0.0, //设置重力参数
        minimumParticleLife: 1,
        maximumParticleLife: 6,
        minimumSpeed: 1.0, //粒子发射的最小速度
        maximumSpeed: 4.0, //粒子发射的最大速度
        startScale: 0.0,
        endScale: 10.0,
        particleSize: 25.0,
      },
      emitterModelMatrix: null,
      translation: null,
      rotation: null,
      hpr: null,
      trs: null,
      scene: null,
      particleSystem: "",
      entity: null,
    };
  },
  components: {},
  created() {},
  mounted() {
    // 模型地址 http://miaotu.szwutu.cn:8100/data1/vaps/3dtiles/jinningdianchang/tileset.json
    Cesium.Ion.defaultAccessToken =
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxNjEwZTc0Ni04MjZmLTRjOTQtODhkZC1jNGY3NmE1MGZhNjMiLCJpZCI6MTg1OTgxLCJpYXQiOjE3MTc1Njg0MTN9.QDYSJkNfZvvb0pCpyLW7-h42cVEbO4hCfbrFLZyrWcg";
    const viewer = new Cesium.Viewer("cesiumContainer", {
      terrainProvider: Cesium.createWorldTerrain({
        url: "https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles",
        requestVertexNormals: true,
        requestWaterMask: true, // 展示地形和水体遮罩
      }),
      // imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
      //   url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
      // }), // 设置底图提供者
      // baseLayerPicker:false,
      baseLayerPicker: false, // 如果设置为false，将不会创建右上角图层按钮。
      geocoder: false, // 如果设置为false，将不会创建右上角查询(放大镜)按钮。
      navigationHelpButton: false, // 如果设置为false，则不会创建右上角帮助(问号)按钮。
      homeButton: false, // 如果设置为false，将不会创建右上角主页(房子)按钮。
      sceneModePicker: false, // 如果设置为false，将不会创建右上角投影方式控件(显示二三维切换按钮)。
      animation: false, // 如果设置为false，将不会创建左下角动画小部件。
      timeline: false, // 如果设置为false，则不会创建正下方时间轴小部件。
      fullscreenButton: false, // 如果设置为false，将不会创建右下角全屏按钮。
      requestRenderMode: true, // 显式渲染，渲染优化
      maximumRenderTimeChange: Infinity, // 请求新帧的时间
      animation: false, //动画控件
      // sceneModePicker: false, //是否显示3D/2D选择器
      // sceneMode: Cesium.SceneMode.SCENE3D, //3d视角展示
    });
    window.viewer = viewer;
    // 设置全局光照，增强3D效果
    // viewer.scene.globe.enableLighting = true;
    viewer.cesiumWidget.creditContainer.style.display = "none";

    // viewer.canvas.addEventListener("click", function () {
    //   const camera = viewer.scene.camera;
    //   const position = camera.position;
    //   const heading = camera.heading;
    //   const pitch = camera.pitch;
    //   const roll = camera.roll;
    //   let xyzCoordinates = [position.x, position.y, position.z];

    //   // 将XYZ坐标转换为Cesium的Cartesian3对象
    //   let cartesian3 = Cesium.Cartesian3.fromArray(xyzCoordinates);

    //   // 将Cartesian3坐标转换为经纬度坐标
    //   let cartographic =
    //     Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3);

    //   // 获取经度、纬度和高程
    //   let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    //   let latitude = Cesium.Math.toDegrees(cartographic.latitude);
    //   let height = cartographic.height;

    //   console.log(`经度: ${longitude}, 纬度: ${latitude}, 高程: ${height}`);
    //   // console.log(position)
    //   console.log(`Heading: ${heading}`);
    //   console.log(`Pitch: ${pitch}`);
    //   console.log(`Roll: ${roll}`);
    // });

    // var tileset = viewer.scene.primitives.add(
    //   new Cesium.Cesium3DTileset({
    //     // url: 'http://data7022.tpddns.cn:9111/1/b3m/tileset.json',
    //     url: "http://miaotu.szwutu.cn:8100/data1/vaps/3dtiles/jinningdianchang/tileset.json",

    //     // modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
    //     //   Cesium.Cartesian3.fromDegrees(113.15051732312735, 41.00220874772237)
    //     // ), // 模型的位置和方向
    //     maximumScreenSpaceError: 2, // 在屏幕上的最大像素错误
    //     maximumNumberOfLoadedTiles: 1000, // 最大加载的瓦片数量
    //     dynamicScreenSpaceError: true, // 是否启用屏幕空间动态误差
    //     skipLevelOfDetail: true, // 是否跳过级别的细节
    //     baseScreenSpaceError: 1024, // 基本的屏幕空间错误
    //     skipLevels: 1, // 跳过的级别
    //     immediatelyLoadDesiredLevelOfDetail: false, // 是否立即加载所需的细节级别
    //     loadSiblingsWithTextures: false, // 是否加载带有纹理的兄弟
    //     // scale: 2.0,
    //     // modelMatrix: Cesium.Matrix4.fromArray([
    //     //   1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
    //     // ]),
    //   })
    // );
    // tileset.position = Cesium.Cartesian3.fromDegrees(
    //   113.15051732312735,
    //   41.00220874772237,
    //   0.0
    // ); // 经纬度和高度
    // 经度: 113.15051732312735, 纬度: 41.00220874772237, 高程: 1806.5328959723404
    // index.js??clonedRuleSet-40.use[0]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/views/HomeView.vue?vue&type=script&lang=js:116 Heading: 0.06946651190102493
    // index.js??clonedRuleSet-40.use[0]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/views/HomeView.vue?vue&type=script&lang=js:117 Pitch: -0.23995335426446407
    // index.js??clonedRuleSet-40.use[0]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/views/HomeView.vue?vue&type=script&lang=js:118 Roll: 0.000018811655211337097
    // 使实体贴地
    // viewer.scene.globe.depthTestAgainstTerrain = true;
    // 将视角飞到模型位置
    // viewer.zoomTo(tileset);

    // viewer.scene.sun.show = true;
    // viewer.scene.moon.show = true;
    // viewer.scene.globe.show = true;
    // viewer.scene.skyAtmosphere.show = false; //隐藏大气圈
    // viewer.scene.skyBox.show = false; //关闭天空盒，否则会显示天空颜色
    // viewer.camera.setView({
    //   destination: Cesium.Cartesian3.fromDegrees(
    //     123.80411007,
    //     31.6286,
    //     12002180.3
    //   ), //经度,纬度,视角高
    // });
    viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(
        110.46464397729298,
        28.10219805438045,
        1693.25906906555
      ), // 纬度、经度和高度
      orientation: {
        heading: 5.130655476066599, // 方向
        pitch: -0.304912350668209, // 倾斜角度
        roll: 0.000036557570545880935, // 滚动角度
      },
    });

    // 离子喷森效果

    // this.viewer = viewer;
    // this.viewModel = {
    //   emissionRate: 5,
    //   gravity: 0.0, //设置重力参数
    //   minimumParticleLife: 1,
    //   maximumParticleLife: 6,
    //   minimumSpeed: 1.0, //粒子发射的最小速度
    //   maximumSpeed: 4.0, //粒子发射的最大速度
    //   startScale: 0.0,
    //   endScale: 10.0,
    //   particleSize: 25.0,
    // };
    this.emitterModelMatrix = new Cesium.Matrix4();
    this.translation = new Cesium.Cartesian3();
    this.rotation = new Cesium.Quaternion();
    this.hpr = new Cesium.HeadingPitchRoll();
    this.trs = new Cesium.TranslationRotationScale();
    this.scene = viewer.scene;
    this.particleSystem = "";
    this.entity = viewer.entities.add({
      //选择粒子放置的坐标
      position: Cesium.Cartesian3.fromDegrees(
        110.46464397729298,
        28.102198054380445
      ),
      // orientation: new Cesium.VelocityOrientationProperty(),
      orientation: Cesium.Transforms.headingPitchRollQuaternion(
        Cesium.Cartesian3.fromDegrees(110.46464397729298, 28.102198054380445), // 中心点位置
        new Cesium.HeadingPitchRoll(
          Cesium.Math.toRadians(0.0),
          Cesium.Math.toRadians(0.0),
          Cesium.Math.toRadians(0.0)
        )
      ),
    });
    this.init();
  },
  computed: {},
  methods: {
    // 离子喷射效果

    init() {
      const _this = this;
      viewer.clock.shouldAnimate = true;
      viewer.scene.globe.depthTestAgainstTerrain = false;
      viewer.trackedEntity = this.entity;
      var particleSystem = this.scene.primitives.add(
        new Cesium.ParticleSystem({
          image: require("@/assets/water10.png"), //生成所需粒子的图片路径
          //粒子在生命周期开始时的颜色
          startColor: new Cesium.Color(1, 1, 1, 0.6),
          //粒子在生命周期结束时的颜色
          endColor: new Cesium.Color(0.8, 0.86, 1, 0.4),
          //粒子在生命周期开始时初始比例
          startScale: _this.viewModel.startScale,
          //粒子在生命周期结束时比例
          endScale: _this.viewModel.endScale,
          //粒子发射的最小速度
          minimumParticleLife: _this.viewModel.minimumParticleLife,
          //粒子发射的最大速度
          maximumParticleLife: _this.viewModel.maximumParticleLife,
          //粒子质量的最小界限
          minimumSpeed: _this.viewModel.minimumSpeed,
          //粒子质量的最大界限
          maximumSpeed: _this.viewModel.maximumSpeed,
          //以像素为单位缩放粒子图像尺寸
          imageSize: new Cesium.Cartesian2(
            _this.viewModel.particleSize,
            _this.viewModel.particleSize
          ),
          //每秒发射的粒子数
          emissionRate: _this.viewModel.emissionRate,
          //粒子系统发射粒子的时间（秒）
          lifetime: 16.0,
          //设置粒子的大小是否以米或像素为单位
          sizeInMeters: true,
          //系统的粒子发射器
          emitter: new Cesium.CircleEmitter(0.2), //BoxEmitter 盒形发射器，ConeEmitter 锥形发射器，SphereEmitter 球形发射器，CircleEmitter圆形发射器
          //回调函数，实现各种喷泉、烟雾效果
          updateCallback: (p, dt) => {
            return this.applyGravity(p, dt);
          },
        })
      );
      this.particleSystem = particleSystem;
      this.preUpdateEvent();
    },

    //场景渲染事件
    preUpdateEvent() {
      let _this = this;
      viewer.scene.preUpdate.addEventListener(function (scene, time) {
        //发射器地理位置
        _this.particleSystem.modelMatrix = _this.computeModelMatrix(
          _this.entity,
          time
        );
        //发射器局部位置
        _this.particleSystem.emitterModelMatrix =
          _this.computeEmitterModelMatrix();
        // 将发射器旋转
        if (_this.viewModel.spin) {
          _this.viewModel.heading += 1.0;
          _this.viewModel.pitch += 1.0;
          _this.viewModel.roll += 1.0;
        }
      });
    },

    computeModelMatrix(entity, time) {
      return entity.computeModelMatrix(time, new Cesium.Matrix4());
    },

    computeEmitterModelMatrix() {
      this.hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, this.hpr);
      this.trs.translation = Cesium.Cartesian3.fromElements(
        -4.0,
        0.0,
        1.4,
        this.translation
      );
      this.trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(
        this.hpr,
        this.rotation
      );

      return Cesium.Matrix4.fromTranslationRotationScale(
        this.trs,
        this.emitterModelMatrix
      );
    },

    applyGravity(p, dt) {
      var gravityScratch = new Cesium.Cartesian3();
      var position = p.position;
      Cesium.Cartesian3.normalize(position, gravityScratch);
      Cesium.Cartesian3.fromElements(
        20 * dt,
        gravityScratch.y * dt,
        -30 * dt,
        gravityScratch
      );
      p.velocity = Cesium.Cartesian3.add(
        p.velocity,
        gravityScratch,
        p.velocity
      );
    },

    removeEvent() {
      viewer.scene.preUpdate.removeEventListener(this.preUpdateEvent, this);
      this.emitterModelMatrix = undefined;
      this.translation = undefined;
      this.rotation = undefined;
      this.hpr = undefined;
      this.trs = undefined;
    },

    //移除粒子特效
    remove() {
      () => {
        return this.removeEvent();
      }; //清除事件
      viewer.scene.primitives.remove(this.particleSystem); //删除粒子对象
      viewer.entities.remove(this.entity); //删除entity
    },

    // 淹没分析
    drawExtent() {
      // 开启深度检测
      window.viewer.scene.globe.depthTestAgainstTerrain = true;
      handler = new Cesium.ScreenSpaceEventHandler(window.viewer.canvas);
      handler.setInputAction((event) => {
        const earthPosition = viewer.scene.pickPosition(event.position);
        if (Cesium.defined(earthPosition)) {
          if (activeShapePoints.length === 0) {
            floatingPoint = this.createPoint(earthPosition);
            activeShapePoints.push(earthPosition);
            const dynamicPositions = new Cesium.CallbackProperty(function () {
              return new Cesium.PolygonHierarchy(activeShapePoints);
            }, false);
            activeShape = this.drawShape(
              dynamicPositions,
              Cesium.Color.fromBytes(64, 157, 253, 50)
            );
          }
          activeShapePoints.push(earthPosition);
          this.tempEntities.push(this.createPoint(earthPosition));
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      handler.setInputAction((event) => {
        if (Cesium.defined(floatingPoint)) {
          const newPosition = viewer.scene.pickPosition(event.endPosition);
          if (Cesium.defined(newPosition)) {
            floatingPoint.position.setValue(newPosition);
            activeShapePoints.pop();
            activeShapePoints.push(newPosition);
          }
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

      handler.setInputAction((event) => {
        activeShapePoints.pop();
        if (activeShapePoints.length < 3) return;

        this.tempEntities.push(this.drawPolyline(activeShapePoints));
        let ploy = this.drawShape(
          activeShapePoints,
          Cesium.Color.fromBytes(64, 157, 253, 20)
        );
        this.tempEntities.push(ploy);
        this.getAreaHeight(activeShapePoints);

        window.viewer.entities.remove(floatingPoint);
        window.viewer.entities.remove(activeShape);
        floatingPoint = undefined;
        activeShape = undefined;
        handler.destroy(); // 关闭事件句柄
        handler = null;
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },
    getAreaHeight(positions) {
      let startP = positions[0];
      let endP = positions[positions.length - 1];
      if (startP.x != endP.x && startP.y != endP.y && startP.z != endP.z)
        positions.push(positions[0]);

      const tempPoints = [];
      for (let i = 0; i < positions.length; i++) {
        var ellipsoid = window.viewer.scene.globe.ellipsoid;
        var cartographic = ellipsoid.cartesianToCartographic(positions[i]);
        var lat = Cesium.Math.toDegrees(cartographic.latitude);
        var lng = Cesium.Math.toDegrees(cartographic.longitude);
        tempPoints.push([lng, lat]);
      }
      var line = turf.lineString(tempPoints);
      var chunk = turf.lineChunk(line, 10, { units: "meters" });

      const tempArray = [];
      chunk.features.forEach((f) => {
        f.geometry.coordinates.forEach((c) => {
          tempArray.push(Cesium.Cartographic.fromDegrees(c[0], c[1]));
        });
      });

      var promise = Cesium.sampleTerrainMostDetailed(
        window.viewer.terrainProvider,
        tempArray
      );
      Cesium.when(promise, (updatedPositions) => {
        const max = Math.max.apply(
          Math,
          updatedPositions.map((item) => {
            return item.height;
          })
        );
        const min = Math.min.apply(
          Math,
          updatedPositions.map((item) => {
            return item.height;
          })
        );
        this.waterHeight = Math.ceil(min);
        this.minWaterHeight = Math.ceil(min);
        this.maxWaterHeight = Math.ceil(max);
        // 禁用绘制按钮
        this.isDraw = !this.isDraw;
      });
    },
    createPoint(worldPosition) {
      const point = window.viewer.entities.add({
        position: worldPosition,
        point: {
          color: Cesium.Color.SKYBLUE,
          pixelSize: 5,
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        },
      });
      return point;
    },
    drawShape(positionData, mat) {
      let shape = window.viewer.entities.add({
        polygon: {
          hierarchy: positionData,
          material: mat,
          outline: true,
          outlineColor: Cesium.Color.SKYBLUE,
          outlineWidth: 4,
        },
      });
      return shape;
    },
    drawPolyline(positions) {
      if (positions.length < 1) return;

      let startP = positions[0];
      let endP = positions[positions.length - 1];
      if (startP.x != endP.x && startP.y != endP.y && startP.z != endP.z)
        positions.push(positions[0]);

      return window.viewer.entities.add({
        name: "polyline",
        polyline: {
          positions: positions,
          width: 2.0,
          material: Cesium.Color.SKYBLUE,
          clampToGround: true,
        },
      });
    },
    induationAnalysis() {
      if (
        Number(this.warningWaterHeight) < Number(this.minWaterHeight) ||
        Number(this.warningWaterHeight) > Number(this.maxWaterHeight)
      ) {
        this.$message({
          message: "预警高度必须在最小高度和最小高度之间",
          type: "warning",
        });
        return;
      }

      let shape = window.viewer.entities.add({
        polygon: {
          hierarchy: activeShapePoints,
          material: Cesium.Color.fromBytes(64, 157, 253, 20),
          extrudedHeight: Number(this.warningWaterHeight),
          outline: true,
          outlineColor: Cesium.Color.RED,
          outlineWidth: 4,
          // perPositionHeight: true
        },
      });
      this.tempEntities.push(shape);

      this.waterHeightShow = true;
      this.waterHeight = Number(this.minWaterHeight);
      const en = window.viewer.entities.add({
        polygon: {
          hierarchy: activeShapePoints,
          extrudedHeight: new Cesium.CallbackProperty(() => {
            return this.waterHeight;
          }, false),
          material: Cesium.Color.fromBytes(64, 157, 253, 150),
        },
      });
      this.tempEntities.push(en);

      this.waterHeightTimeer = setInterval(() => {
        this.waterHeight += Number(this.speed);

        let l =
          this.speed.split(".").length > 1
            ? this.speed.split(".")[1].length
            : 0;
        this.waterHeight = Number(this.waterHeight.toFixed(l));
        this.maxWaterHeight = Number(this.maxWaterHeight);
        this.minWaterHeight = Number(this.minWaterHeight);
        if (
          this.waterHeight > this.maxWaterHeight ||
          this.waterHeight < this.minWaterHeight
        ) {
          clearInterval(this.waterHeightTimeer);
          this.waterHeight =
            this.waterHeight > this.maxWaterHeight
              ? this.maxWaterHeight
              : this.minWaterHeight;
        }
      }, 1000);
    },
    /**
     * @author:
     * @Date: 2022-04-11 16:44:42
     * @note: 注意事项
     * @description: 清除当前页面所有数据
     */
    clearAllEntities() {
      if (this.waterHeightTimeer) {
        clearInterval(this.waterHeightTimeer);
      }
      this.positions = [];
      const length = this.tempEntities.length;
      for (let f = 0; f < length; f++) {
        window.viewer.entities.remove(this.tempEntities[f]);
      }
      this.tempEntities = [];
      this.waterHeightShow = false;
      activeShapePoints = [];
      this.warningWaterHeight = 0;
      this.isDraw = !this.isDraw;
      floatingPoint = undefined;
      activeShape = undefined;
      if (handler) {
        handler.destroy(); // 关闭事件句柄
        handler = undefined;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.box {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  // overflow: hidden;
  #cesiumContainer {
    width: 100%;
    height: 100%;
  }
  .div {
    width: 400px;
    height: 300px;
    position: absolute;
    top: 0px;
    left: 0px;
    color: #ffffff;
  }
}
</style>